//
//  Matrix.m
//  Mockup
//
//  Created by Bernardo Quibiana on 3/26/10.
//  Copyright 2010 Mac-Easy@USC. All rights reserved.
//

#import "Matrix.h"


@implementation Matrix

@synthesize rowSize, colSize;
@synthesize core;

/*
 * Initializing a matrix
 */

- (id)initWithMatrix:(Matrix *)matrix {
	if (self = [super init]) {
		self.rowSize = matrix.rowSize;
		self.colSize = matrix.colSize;
		core = [NSMutableArray arrayWithArray:matrix.core];
	}
	
	return self;
}

- (id)initWithMatrix:(Matrix *)matrix rowRange:(NSRange) rowRange colRange:(NSRange) colRange wrapAround:(BOOL) wrap{
	if (self = [super init]) {
		NSUInteger startIndex;
		self.rowSize = rowRange.length;
		self.colSize = colRange.length;
#ifdef DEBUG	
		NSLog(@"Matrix:\trow: %d\t%d\tcol: %d\t%d", rowRange.location, rowRange.length, colRange.location, colRange.length);
#endif
		core = [NSMutableArray arrayWithCapacity:(rowRange.length * colRange.length)];
		
		if (!wrap) {
			if ((rowRange.location + rowRange.length) > matrix.rowSize) {
				// invalid row range
				NSLog(@"Matrix:\tInvalid row range");
			} else if ((colRange.location + colRange.length) > matrix.colSize) {
				// invalid col range
#ifdef DEBUG 
				NSLog(@"Matrix:\tInvalid col range");
#endif
			}
		} 
 		
		for (int i = 0; i < rowRange.length; i++) {
			startIndex = i * colRange.length;
			for (int j = 0; j < colRange.length; j++) {
#ifdef DEBUG
				NSLog(@"core index: %d\trow: %d\tcol: %d", startIndex + j, rowRange.location + i, colRange.location + j);
#endif
				[core insertObject: [matrix objectAtRow:(rowRange.location + i) % matrix.rowSize 
												 andCol:(colRange.location + j) % matrix.colSize] 
						   atIndex:(startIndex + j)];
			}
		}
		
#ifdef DEBUG
		NSLog(@"Matrix:\n%@", [self description]);
#endif
		
	}
	
	return self;
}

- (id)initWithRowSize: (NSUInteger) rows colSize:(NSUInteger) cols{
	if (self = [super init]) {
		self.rowSize = rows;
		self.colSize = cols;
		core = [NSMutableArray arrayWithCapacity:(rows * cols)];
	}
	
	return self;
}

- (id)initWithArray:(NSArray *) array rowSize:(NSUInteger) rows colSize:(NSUInteger) cols{
	if (self = [super init]) {
		self.rowSize = rows;
		self.colSize = cols;
		core = [NSMutableArray arrayWithArray:array];
	}
	
	return self;
}

- (id)initWithContentsOfFile:(NSString *) path rowSize:(NSUInteger) rows colSize:(NSUInteger) cols{
	if (self = [super init]) {
		self.rowSize = rows;
		self.colSize = cols;
		core = [[NSMutableArray alloc] initWithContentsOfFile:path];
		//[core retain];
		
		if (core == nil) {
			NSLog(@"Matrix:\tCould not find/open : %@", path);
		} else if ([core count] < (rows * cols)) {
			
		}
	}
	
	return self;
}
	
- (id)initWithContentsOfURL:(NSURL *) url rowSize:(NSUInteger) rows colSize:(NSUInteger) cols{
	if (self = [super init]) {
		self.rowSize = rows;
		self.colSize = cols;
		core = [[NSMutableArray alloc] initWithContentsOfURL:url];
		//[core retain];
		if (core == nil) {
			
		} else if ([core count] < (rows * cols)) {
			
		}
	}
	
	return self;
}


/*
 * Creating a matrix
 */

+ (id)matrixWithMatrix:(Matrix *) matrix {
	Matrix * _matrix = [[Matrix alloc] initWithMatrix:matrix];
	
	return [_matrix autorelease];
}

+ (id)matrixWithMatrix:(Matrix *)matrix rowRange:(NSRange)rowRange colRange:(NSRange)colRange wrapAround:(BOOL)wrap {
	Matrix * _matrix = [[Matrix alloc] initWithMatrix:matrix rowRange:rowRange colRange:colRange wrapAround:wrap];
	
	return [_matrix autorelease];
}

+ (id)matrixWithContentsOfArray:(NSArray *)array rowSize:(NSUInteger) rows colSize:(NSUInteger)cols {
	Matrix * matrix = [[Matrix alloc] initWithArray:array rowSize:rows colSize:cols];
	
	return [matrix autorelease];
}

+ (id)matrixWithContentsOfFile:(NSString *) path rowSize:(NSUInteger) rows colSize:(NSUInteger) cols{
	Matrix * matrix = [[Matrix alloc] initWithContentsOfFile:path rowSize:rows colSize:cols];
	
	return [matrix autorelease];
}

+ (id)matrixWithContentsOfURL:(NSURL *)url rowSize:(NSUInteger)rows colSize:(NSUInteger)cols {
	Matrix * matrix = [[Matrix alloc] initWithContentsOfURL:url rowSize:rows colSize:cols];
	
	return [matrix autorelease];
}


/*
 * Dealloc
 */
- (void) dealloc {
	[core release];
	
	[super dealloc];
}

/*
 *  Querying a matrix
 */

- (BOOL)containsObject:(id) object{
	return [core containsObject:object];
}

- (void)getObjects:(id *) buffer {
	[core getObjects:buffer];
}

- (void)getObjects:(id *) buffer row:(NSUInteger) row range:(NSRange) range{
	NSRange _range;
	if (row >= rowSize) {
		// invalid row
	} else if ((range.location + range.length) >= colSize){
		// invalid range
	}
	_range  = NSMakeRange(row * colSize + range.location, range.length);
	[core getObjects:buffer range:_range];
}

- (void)getObjects:(id *) buffer col:(NSUInteger) col range:(NSRange) range{
	if (col >= colSize) {
		// invalid col
	} else if ((range.location + range.length) >= rowSize){
		// invalid range
	}
	NSArray * array = [self getCol:col];
	[array getObjects:buffer range:range];
	//[array release];
}

- (void)getObjects:(id *) buffer indexRange:(NSRange) range{
	if ((range.location + range.length) >= (rowSize * colSize)) {
		// invalid range
	}
	[core getObjects:buffer range:range];
}

- (id)objectAtIndex:(NSUInteger) index{
	if (index >= (rowSize * colSize)) {
		// invalid index
	}
	return [core objectAtIndex:index];
}

- (id)objectAtRow:(NSUInteger) row andCol:(NSUInteger) col{
	if (row >= rowSize || col >= colSize) {
		// invalid row/col
	}
	return [core objectAtIndex:(row * colSize + col)];
}

- (NSArray *)getRow:(NSUInteger) row{
	if (row >= rowSize) {
		// invalid row
	}
	NSUInteger startIndex = row * colSize;
	NSMutableArray * array = [[NSMutableArray arrayWithCapacity:colSize] autorelease];
	for (int i = 0; i < colSize; i++) {
		[array replaceObjectAtIndex:i withObject: [core objectAtIndex:(startIndex + i)]];
	}
	
	return array;
}

- (NSArray *)getCol:(NSUInteger) col{
	if (col >= colSize) {
		// invalid col
	}
	NSMutableArray * array = [[NSMutableArray arrayWithCapacity:rowSize] autorelease];
	for (int i = 0; i < rowSize; i++) {
		[array replaceObjectAtIndex:i withObject: [core objectAtIndex:(i * colSize + col)]];
	}
	
	return array;
}

- (NSEnumerator *)objectEnumerator{
	return nil;
}


/*
 * Finding objects in the matrix
 */
- (NSUInteger)indexOfObject:(id) object{
	return [core indexOfObject:object];
}

- (NSUInteger)indexOfObject:(id) object inRange:(NSRange) range{
	return [core indexOfObject:object inRange:range];
}

- (NSUInteger)indexOfObjectIdenticalTo:(id) object{
	return [core indexOfObjectIdenticalTo:object];
}

/*
 * Inserting objects
 */
- (void)insertObject:(id)object atRow:(NSUInteger) row andCol:(NSUInteger) col {
	if (row >= rowSize || col >= colSize) {
		// invalid row/col
	}
	[self.core insertObject:object atIndex:(row * colSize + col)];
}

- (void)insertObject:(id)object atIndex:(NSUInteger) index {
	if (index >= (rowSize * colSize)) {
		// invalid index
	}
	[self.core insertObject:object atIndex:index];
}

/*
 * Replacing objects
 */
- (void)replaceObjectAtRow:(NSUInteger) row andCol:(NSUInteger) col withObject:(id) object{
	if (row >= rowSize || col >= colSize) {
		// invalid row/col
	}
	[core replaceObjectAtIndex:(row * colSize + col) withObject:object];
}

- (void)replaceObjectAtIndex:(NSUInteger) index withObject:(id) object{
	if (index >= (rowSize * colSize)) {
		// invalid index
	}
	[core replaceObjectAtIndex:index withObject:object];
}

- (void)replaceObjectsAtIndexes:(NSIndexSet *) indexes withObject:(id) object{
	[core replaceObjectsAtIndexes:indexes withObjects:object];
}

/*
 *
 */

- (NSString *) description {
	NSMutableString * str = [NSMutableString stringWithCapacity:100];
	
	[str appendFormat: @"Matrix\nRow size: %d\tCol size: %d\n", rowSize, colSize];
	for (int i = 0; i < rowSize; i++) {
		for (int j = 0; j < colSize; j++) {
			[str appendFormat:@"%@\t", [[core objectAtIndex:(i * colSize + j)] description]];
		}
		[str appendString:@"\n"];
	}
			 
	return str;
}

- (BOOL)writeToFile:(NSString *) path atomically:(BOOL) flag{
	return [core writeToFile:path atomically:flag];
}

- (BOOL)writeToURL:(NSURL *) url atomically:(BOOL) flag {
	return [core writeToURL:url atomically:flag];
}

@end
